package com.it.lock.service.impl;

import com.it.lock.service.RedisLockService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


@Slf4j
@Service
@Scope("prototype") //配置为多例
public class RedisLockServiceImpl implements RedisLockService {

    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public String getLock() throws InterruptedException {
        String uuid = UUID.randomUUID().toString();
        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", uuid, 30000, TimeUnit.MILLISECONDS);
        if (lock) {
            log.info("获取锁成功***********");


            String lockValue = stringRedisTemplate.opsForValue().get("lock");
            if (uuid.equals(lockValue)) {
                stringRedisTemplate.delete("lock");
                log.info("释放锁*********");
            }
            return "获取锁成功，执行完成";

        } else {
            log.info("获取锁失败");
            return "获取锁失败";
        }

    }
    //增强了锁释放时的原子操作,
    //  原子操作 当前uuid和redis中value进行对比 如果相同删除，不相同则不删除
    @Override
    public String getLock2() throws InterruptedException {
        String uuid = UUID.randomUUID().toString();
        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", uuid, 30000, TimeUnit.MILLISECONDS);
        if (lock) {
            log.info("获取锁成功***********");
            try{
                log.info("执行业务");
                //Thread.sleep(5000);
            }finally {
                String  script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
                Long lock2 =  stringRedisTemplate.execute(new DefaultRedisScript<Long>(script,Long.class), Arrays.asList("lock"),uuid);
                if(lock2==1){
                    log.info("锁释放成功");
                }else{
                    log.info("锁释放失败");
                }

            }
            return "获取锁成功，执行完成";

        } else {
            log.info("获取锁失败");
            return "获取锁失败";
        }

    }

}






